package com.lovi.notepaper.activities;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.util.Patterns;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;

import com.lovi.notepaper.R;
import com.lovi.notepaper.adapters.NotesAdapter;
import com.lovi.notepaper.database.NoteDatabase;
import com.lovi.notepaper.entities.Note;
import com.lovi.notepaper.listeners.NotesListeners;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements NotesListeners {

    //请求码自定义的。定义原因是：为了避免请求码重复，通常会将请求码定义为常量，并在整个应用中使用同一个请求码。

    // 添加笔记请求码
    private static final int REQUEST_CODE_ADD_NOTE = 1;
    // 更新笔记请求码（包括了删除和更新）
    private static final int REQUEST_CODE_UPDATE_NOTE = 2;
    // 显示笔记请求码
    private static final int REQUEST_CODE_SHOW_NOTES = 3;
    // 选择图片请求码
    private static final int REQUEST_CODE_SELECT_IMAGE = 4;
    // 存储权限请求码
    private static final int REQUEST_CODE_STORAGE_PERMISSION = 5;

    // 笔记列表控件
    private RecyclerView noteRecyclerView;
    // 笔记列表数据源
    private List<Note> noteList;
    // 笔记列表适配器
    private NotesAdapter noteAdapter;

    // 当前被选中的笔记在列表中的位置
    private int clickedNotePosition = -1;

    // 添加 URL 的对话框
    private AlertDialog dialogAddURL;

    //切换按钮
    private Button button;

    // 定义颜色数组
    int[] colors = {Color.parseColor("#4158D0"), Color.parseColor("#8EC5FC"), Color.parseColor("#00DBDE"), Color.parseColor("#D9AFD9")};
    int currentColorIndex = 0;  // 当前颜色的索引


    // 设置当前活动界面
    @SuppressLint("UseCompatLoadingForDrawables")//固定写法：告诉 Android Lint 工具，忽略使用 getDrawable() 方法时出现的警告信息。
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        // 获取添加笔记按钮控件
        ImageView imageAddNoteMain = findViewById(R.id.imageAddNoteMain);
        // 设置添加笔记按钮的点击事件
        imageAddNoteMain.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 打开创建笔记的活动界面，并传递请求码 REQUEST_CODE_ADD_NOTE
                startActivityForResult(new Intent(getApplicationContext(), CreateNoteActivity.class), REQUEST_CODE_ADD_NOTE);
            }
        });

        // 实例化 RecyclerView 控件
        noteRecyclerView = findViewById(R.id.notesRecyclerView);
        button = findViewById(R.id.button1);
        // 设置 RecyclerView 的布局管理器为瀑布流布局，列数为 2，方向为垂直方向
        noteRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL));

        // 初始化笔记列表数据源和适配器
        noteList = new ArrayList<>();
        noteAdapter = new NotesAdapter(noteList,this);//展示笔记列表
        // 将适配器设置给 RecyclerView 控件
        noteRecyclerView.setAdapter(noteAdapter);//自然而然的事情

        // 获取笔记列表数据并显示在界面上（展示所有，新增，修改，删除都在这，并且是异步的哦！）
        getNotes(REQUEST_CODE_SHOW_NOTES,false);

        // 获取搜索输入框控件
        EditText inputSearch = findViewById(R.id.inputSearch);
        // 添加搜索输入框文本变化监听器
        inputSearch.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                // 取消之前的搜索任务（让定时器取消，不进入搜索，当改变的时候）
                noteAdapter.cancelTimer();
                // 在日志中打印“onTextChanged”
                Log.d("Timer","onTextChanged");
            }

            @Override
            public void afterTextChanged(Editable editable) {
                // 如果笔记列表数据源不为空，就进行搜索
                if(noteList.size() != 0){
                    noteAdapter.searchNotes(editable.toString());
                }
            }
        });

        // 绑定快捷按钮的点击事件
//        findViewById(R.id.imageAddNote).setOnClickListener(v -> {
//            startActivityForResult(new Intent(getApplicationContext(), CreateNoteActivity.class),REQUEST_CODE_ADD_NOTE);
//        });
//
//        findViewById(R.id.imageAddImage).setOnClickListener(v -> {
//            // 如果没有读取存储权限，就向系统请求权限
//            if(ContextCompat.checkSelfPermission(getApplicationContext(),
//                    Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
//                ActivityCompat.requestPermissions(MainActivity.this,
//                        new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},REQUEST_CODE_STORAGE_PERMISSION);
//            }else{ // 否则，打开系统图库选择图片
//                selectImage();
//            }
//        });
//
//        findViewById(R.id.imageAddWebLink).setOnClickListener(v -> {
//            // 显示添加 URL 的对话框
//            showAddUrlDialog();
//        });
        /**
         * 播放一个背景动画,渐变色切换
         * 在 XML 文件中定义 <animation-list> 标签来实现逐帧动画
         */
        // 获取活动界面根布局控件
//        ConstraintLayout mainLayout = findViewById(R.id.layout_main);
//        // 获取动画背景并设置进入和退出的淡入淡出时间
//        AnimationDrawable animationDrawable = (AnimationDrawable) mainLayout.getBackground();
//        animationDrawable.setEnterFadeDuration(2500);
//        animationDrawable.setExitFadeDuration(5000);
//        // 开始播放动画
//        animationDrawable.start();


        // 在按钮点击事件中调用以下代码，切换背景颜色
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//                // 获取活动界面根布局控件
//                ConstraintLayout mainLayout = findViewById(R.id.layout_main);
//                // 设置背景颜色
//                mainLayout.setBackgroundColor(colors[currentColorIndex]);
//                // 更新当前颜色的索引
//                currentColorIndex = (currentColorIndex + 1) % colors.length;

                //试试看咯
                // 切换图片
                ConstraintLayout mainLayout = findViewById(R.id.layout_main);
                AnimationDrawable animationDrawable = (AnimationDrawable) mainLayout.getBackground();
                animationDrawable.selectDrawable((animationDrawable.getFrame(0) == animationDrawable.getCurrent()) ? 1 : 0);
            }
        });


    }
    /*
    主要就是判断输入的 URL 是否为空或者是否是合法的 URL 地址，
    如果不合法则弹出提示信息，如果合法则关闭对话框并将输入的 URL 地址作为参数传递给创建笔记的活动界面。
     */
    private void showAddUrlDialog(){
        // 判断 dialogAddURL 是否为空，如果为空，则创建对话框
        if(dialogAddURL == null){
            // 创建 AlertDialog.Builder 对象
            AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
            // 获取布局文件 layout_add_url，并填充到对话框中
            View view = LayoutInflater.from(this).inflate(R.layout.layout_add_url,(ViewGroup)findViewById(R.id.layoutAddUrlContainer));
            builder.setView(view);
            // 使用 builder.create() 方法创建对话框，并将其保存到 dialogAddURL 变量中
            dialogAddURL = builder.create();
            // 设置对话框的背景为透明色
            if(dialogAddURL.getWindow() != null){
                dialogAddURL.getWindow().setBackgroundDrawable(new ColorDrawable(0));
            }

            // 获取输入 URL 的 EditText 控件
            final EditText inputUrl = view.findViewById(R.id.inputURL);
            // 将输入 URL 的 EditText 控件设置为焦点
            inputUrl.requestFocus();

            // 监听添加按钮的点击事件
            view.findViewById(R.id.textAdd).setOnClickListener(v -> {
                // 判断输入 URL 是否为空，如果是，则弹出提示信息
                if(inputUrl.getText().toString().trim().isEmpty()){
                    Toast.makeText(MainActivity.this,"请输入url",Toast.LENGTH_SHORT).show();
                    return;
                }else if(!Patterns.WEB_URL.matcher(inputUrl.getText().toString()).matches()){
                    // 判断输入 URL 是否是合法的 URL 地址，如果不是，则弹出提示信息
                    Toast.makeText(MainActivity.this,"请输入有效的url",Toast.LENGTH_SHORT).show();
                    return;
                }else{
                    // 关闭对话框，并将输入的 URL 地址作为参数传递给创建笔记的活动界面
                    dialogAddURL.dismiss();
                    Intent intent = new Intent(getApplicationContext(),CreateNoteActivity.class);
                    intent.putExtra("isFromQuickActions",true);
                    intent.putExtra("quickActionType","URL");
                    intent.putExtra("URL",inputUrl.getText().toString());
                    startActivityForResult(intent,REQUEST_CODE_ADD_NOTE);
                }
            });

            // 监听取消按钮的点击事件，关闭对话框
            view.findViewById(R.id.textCancel).setOnClickListener(v -> {
                dialogAddURL.dismiss();
            });
        }

        // 显示对话框
        dialogAddURL.show();
    }

    /*
    主要就是在 selectImage() 方法中创建 Intent 对象，并检查是否有可以处理该 Intent 的 Activity，如果有，
    则启动该 Activity 并传递请求码 REQUEST_CODE_SELECT_IMAGE；在 onRequestPermissionsResult()
    方法中处理请求权限的结果，判断是否允许了存储权限，如果是，则调用 selectImage() 方法，否则弹出提示信息。
     */
    private void selectImage() {
        // 创建 Intent 对象，用于打开系统的图库应用
        Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        // 检查是否有可以处理该 Intent 的 Activity，如果有，则启动该 Activity 并传递请求码 REQUEST_CODE_SELECT_IMAGE
        if(intent.resolveActivity(getPackageManager()) != null){
            startActivityForResult(intent,REQUEST_CODE_SELECT_IMAGE);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        // 处理请求权限的结果
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode == REQUEST_CODE_STORAGE_PERMISSION && grantResults.length > 0){
            // 判断是否允许了存储权限，如果是，则调用 selectImage() 方法，否则弹出提示信息
            if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
                selectImage();
            }else {
                Toast.makeText(this,"权限被拒绝",Toast.LENGTH_SHORT).show();
            }
        }
    }

    /*
    视图更新笔记列表
    主要就是在 getNotes() 方法中创建 GetNotesTask 类，用于异步获取笔记列表，在 onPostExecute() 方法中根据 requestCode 分别进行不同的操作；
    在 onActivityResult() 方法中根据 requestCode 和 resultCode 分别进行不同的操作，其中包括重新获取所有笔记列表、更新一条笔记、从图库中选择图片等。
     */
    private void getNotes(final int requestCode, final boolean isNoteDeleted){
        // 创建 GetNotesTask 类，继承自 AsyncTask，用于异步获取笔记列表
        class GetNotesTask extends AsyncTask<Void,Void, List<Note>>{

            // 在后台线程中获取笔记列表
            @Override
            protected List<Note> doInBackground(Void... voids) {
                return NoteDatabase.getNoteDatabase(getApplicationContext()).noteDao().getAllNotes();
            }

            // 在主线程中更新 UI，根据 requestCode 分别进行不同的操作
            @SuppressLint("NotifyDataSetChanged")//忽略使用 notifyDataSetChanged() 方法时产生的警告信息。
            @Override
            protected void onPostExecute(List<Note> notes) {
                super.onPostExecute(notes);
                if(requestCode == REQUEST_CODE_SHOW_NOTES){
                    // 显示所有笔记列表
                    noteList.addAll(notes);
                    noteAdapter.notifyDataSetChanged();
                }else if(requestCode == REQUEST_CODE_ADD_NOTE){
                    // 向笔记列表中添加一条新的笔记，并使新的笔记显示在列表的第一个位置。并且滚动到顶部
                    noteList.add(0,notes.get(0));//获取原来第一个笔记，然后在前面插入新的笔记。
                    noteAdapter.notifyItemInserted(0);
                    noteRecyclerView.smoothScrollToPosition(0);
                }else if(requestCode == REQUEST_CODE_UPDATE_NOTE){
                    // 更新一条笔记
                    noteList.remove(clickedNotePosition);//为了避免重复，先在list里删除了笔记，而数据库里并没有删除（更新完再插入）
                    if(isNoteDeleted){
                        // 删除一条笔记
                        noteAdapter.notifyItemRemoved(clickedNotePosition);//通知更新视图
                    }else{
                        // 修改一条笔记
                        noteList.add(clickedNotePosition,notes.get(clickedNotePosition));
                        noteAdapter.notifyItemChanged(clickedNotePosition);////通知更新视图
                    }
                }
            }
        }

        // 启动 GetNotesTask 异步任务
        new GetNotesTask().execute();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == REQUEST_CODE_ADD_NOTE && resultCode == RESULT_OK){
            // 如果是添加笔记操作，则重新获取所有笔记列表
            getNotes(REQUEST_CODE_ADD_NOTE,false);
        }else if(requestCode == REQUEST_CODE_UPDATE_NOTE && resultCode == RESULT_OK){
            // 如果是更新笔记操作
            if(data != null){
                // 获取传递过来的数据（是否删除笔记）
                getNotes(REQUEST_CODE_UPDATE_NOTE,data.getBooleanExtra("isNoteDeleted",false));
            }
        }else if (requestCode == REQUEST_CODE_SELECT_IMAGE && resultCode == RESULT_OK){
            // 如果是从图库中选择图片
            if(data != null){
                // 获取选择的图片 Uri
                Uri selectedImageUri = data.getData();
                if(selectedImageUri != null){
                    try{
                        // 将 Uri 转换为文件路径
                        String selectedImagePath = getPathFromUri(selectedImageUri);
                        // 打开 CreateNoteActivity，并传递图片路径等信息
                        Intent intent = new Intent(getApplicationContext(),CreateNoteActivity.class);
                        intent.putExtra("isFromQuickActions",true);
                        intent.putExtra("quickActionType","image");
                        intent.putExtra("imagePath",selectedImagePath);
                        startActivityForResult(intent,REQUEST_CODE_ADD_NOTE);
                    }catch (Exception e){
                        Toast.makeText(this,e.getMessage(),Toast.LENGTH_SHORT).show();
                    }
                }
            }
        }
    }

    /**
     * 处理笔记列表中笔记项的点击事件，将用户选中的笔记信息传递给 CreateNoteActivity，以便更新笔记或查看笔记详情。
     * @param note 点击的笔记对象
     * @param position 点击的笔记在列表中的位置
     */
    @Override
    public void onNoteClicked(Note note, int position) {
        // 当前被选中的序号
        clickedNotePosition = position;
        // 输出当前选中的序号
        System.out.println("当前选中的序号:" + clickedNotePosition);
        // 创建 Intent，并传递笔记信息
        Intent intent = new Intent(getApplicationContext(), CreateNoteActivity.class);
        intent.putExtra("isViewOrUpdate", true);
        intent.putExtra("note", note);
        // 启动 CreateNoteActivity，请求更新笔记
        startActivityForResult(intent, REQUEST_CODE_UPDATE_NOTE);
    }

    /**
     * 根据 Uri 获取文件路径
     * @param contentUri 图片 Uri
     * @return 文件路径
     */
    private String getPathFromUri(Uri contentUri) {
        // 初始化变量 filePath，用于保存获取到的文件路径
        String filePath;
        // 通过 getContentResolver().query() 方法获取一个 Cursor 对象，该 Cursor 对象用于查询 Uri 对应的数据源
        Cursor cursor = getContentResolver().query(contentUri, null, null, null, null);
        // 如果查询失败，则使用 getPath() 方法获取 Uri 对应的路径，并将其赋值给 filePath 变量
        if (cursor == null) {
            filePath = contentUri.getPath();
        }
        // 如果查询成功，则通过 Cursor 对象获取文件路径，并将其赋值给 filePath 变量
        else {
            // 将 Cursor 移动到第一行
            cursor.moveToFirst();
            // 获取 _data 列的索引
            int index = cursor.getColumnIndex("_data");
            // 获取 _data 列的值，即文件的路径，并将其赋值给 filePath 变量
            filePath = cursor.getString(index);
            // 关闭 Cursor 对象
            cursor.close();
        }
        // 返回获取到的文件路径
        return filePath;
    }


}